#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
 
#include "data_type.h"
#include "alloc.h"
#include "memfunc.h"
#include "basefunc.h"
#include "struct_deal.h"
#include "crypto_func.h"
#include "memdb.h"
#include "message.h"
#include "ex_module.h"
#include "sys_func.h"
#include "tcm_constants.h"
#include "tcm_structures.h"
#include "tcmfunc.h"
#include "tcm_cube_struct.h"
#include "tcm_key_manage.h"
#include "tcm_key_desc.h"
#include "tcm_pik_desc.h"
#include "quote_report.h"
// add para lib_include
   BYTE Buf[DIGEST_SIZE*16];
   RECORD(TCM_KEY_DESC,REMOTE_KEYSET) * remote_keyset_get_byname (char * name);
   RECORD(TCM_KEY_DESC,LOCAL_KEYSET) * local_keyset_get_byname (char * name);
  int get_uuid_name(BYTE * uuid, char * name, char * path);

int quote_report_init(void * sub_proc, void * para)
{
	int ret;

	// add yorself's module init func here
	return 0;
}

int quote_report_start(void * sub_proc, void * para)
{
	int ret;
	void * recv_msg;
	int type;
	int subtype;
	// add yorself's module exec func here

	RECORD(MESSAGE,SIZED_BINDATA) * key_blob;
	MSG_EXPAND * expand;	

	while(1)
	{
		usleep(time_val.tv_usec);
		ret=ex_module_recvmsg(sub_proc,&recv_msg);
		if(ret<0)
			continue;
		if(recv_msg==NULL)
			continue;
		type=message_get_type(recv_msg);
		subtype=message_get_subtype(recv_msg);
		if(!memdb_find_recordtype(type,subtype))
		{
			printf("message format (%d %d) is not registered!\n",
			message_get_type(recv_msg),message_get_subtype(recv_msg));
			continue;
		}
	
		if((type==TYPE(TCM_PIK_DESC))&&(subtype==SUBTYPE(TCM_PIK_DESC,PCRQUOTE)))
		{
			ret=proc_quote_choice(sub_proc,recv_msg);
		}
        else
        {
			ret=proc_quote_expand_choice(sub_proc,recv_msg);
        }
			
	}
	return 0;
}

int proc_quote_choice(void * sub_proc,void * recv_msg)
{
	int ret=0;

	BYTE local_uuid[DIGEST_SIZE];	
	BYTE user_name[DIGEST_SIZE];
	
	BYTE Namebuf[DIGEST_SIZE*4];
	BYTE nonce[DIGEST_SIZE];
	UINT32 result;
	
	void * new_msg;

	MSG_EXPAND * msg_expand;

	RECORD(TCM_PIK_DESC,PCRQUOTE) * pcrquote;

	int key_len;
	ret=message_get_record(recv_msg,&pcrquote,0);
	if(ret<0)
		return ret;
	if(pcrquote->signLen==0)
		ret=proc_pcrquote_report(sub_proc,pcrquote,recv_msg);
	else
		ret=proc_pcrquote_verify(sub_proc,pcrquote,recv_msg);
	return ret;
}

int proc_quote_expand_choice(void * sub_proc,void * recv_msg)
{
	int ret=0;

	BYTE local_uuid[DIGEST_SIZE];	
	BYTE user_name[DIGEST_SIZE];
	
	BYTE Namebuf[DIGEST_SIZE*4];
	BYTE nonce[DIGEST_SIZE];
	UINT32 result;
	
	void * new_msg;

	MSG_EXPAND * msg_expand;

	RECORD(TCM_PIK_DESC,PCRQUOTE) * pcrquote;

	int key_len;
	ret=message_remove_expand(recv_msg,TYPE_PAIR(TCM_PIK_DESC,PCRQUOTE),&msg_expand);
	if(ret<0)
		return ret;
    if(msg_expand == NULL)
        return ex_module_sendmsg(sub_proc,recv_msg);        
    pcrquote=msg_expand->expand;
    if(pcrquote==NULL)
        return ex_module_sendmsg(sub_proc,recv_msg);

	if(pcrquote->signLen==0)
		ret=proc_pcrquote_expand_report(sub_proc,pcrquote,recv_msg);
	else
		ret=proc_pcrquote_expand_verify(sub_proc,pcrquote,recv_msg);
	return ret;
}

int proc_pcrquote_report(void * sub_proc,RECORD(TCM_PIK_DESC,PCRQUOTE) * pcrquote,void * recv_msg)
{
	int ret=0;

	BYTE local_uuid[DIGEST_SIZE];	
	BYTE user_name[DIGEST_SIZE];
	
	BYTE Namebuf[DIGEST_SIZE*4];
	BYTE nonce[DIGEST_SIZE];
	UINT32 result;
	void * new_msg;

	MSG_EXPAND * msg_expand;
        RECORD(VTCM_IN_KEY,TCM_BIN_PUBKEY) * pubkey;
        RECORD(TCM_KEY_MANAGE,PRIVATE_KEY) * private_key;
        RECORD(TCM_KEY_DESC,LOCAL_KEYSET) * local_keyset;

	int key_len;
	int blob_len;
    	UINT32 authHandle;
    	UINT32 pikHandle;
    	UINT32 signkeyHandle;
   	BYTE SignBuf[256];
    	int  Buflen;
    	int SignLen;

        local_keyset=local_keyset_get_byname(pcrquote->userinfo.username);
        if(local_keyset==NULL)
                return -EINVAL;

	printf("begin key load !\n");

	// get receiver's remote keyset

        TCM_KEY * verifykey;

        verifykey=malloc(sizeof(*verifykey));
        if(verifykey==NULL)
            return -EINVAL;

	get_uuid_name(local_keyset->pik_uuid,Namebuf,"tcmkey/");
   	ret = TCM_ExLoadTcmKey(verifykey, Namebuf);
   	 if(ret!=0)
    	{
        	printf("ExLoadTcmKey error!\n");
        	return -EINVAL;
    	}

    	ret=TCM_APCreate(TCM_ET_SMK, NULL, "sss", &authHandle);
    	printf("authHandle is : %x\n",authHandle);
    	if(ret<0)
    	{
        	printf("TCM_APCreate failed!\n");
        	return -EINVAL;
    	}
    	ret=TCM_LoadKey(0x40000000,authHandle,verifykey,&pikHandle);
    	if(ret<0)
    	{
        	printf("TCM_LoadKey failed!\n");
        	return -EINVAL;
    	}
    	ret=TCM_APTerminate(authHandle);
    	if(ret<0)
    	{
		printf("TCM_APTerminate %x failed!\n",authHandle);
		return -EINVAL;	
    	}	
    	// Quote the data
   	ret=TCM_APCreate(TCM_ET_KEYHANDLE, pikHandle, "kkk", &authHandle);
    	printf("pik authHandle is : %x\n",authHandle);
    	if(ret<0)
    	{
		printf("TCM_APCreate failed!\n");
		return -EINVAL;	
    	}	

    	ret=TCM_Quote(pikHandle,authHandle,pcrquote->nonce,&pcrquote->pcrComp,
		SignBuf,&SignLen);

    	ret=TCM_APTerminate(authHandle);
    	if(ret<0)
    	{
		printf("TCM_APTerminate %x failed!\n",authHandle);
		return -EINVAL;	
    	}	

    	ret=TCM_EvictKey(pikHandle);
    	if(ret<0)
    	{
		printf("TCM_EvictKey %x failed!\n",pikHandle);
		return -EINVAL;	
    	}	

//	new_msg=message_clone(recv_msg);

	pcrquote->signLen=SignLen;
	pcrquote->signData=Talloc0(SignLen);
	Memcpy(pcrquote->signData,SignBuf,SignLen);
	//Strncpy(pcrquote->userinfo.username,local_keyset->user_name,32);
	//Memcpy(pcrquote->userinfo.node_uuid,local_uuid,DIGEST_SIZE);

	new_msg=message_create(TYPE_PAIR(TCM_PIK_DESC,PCRQUOTE),recv_msg);
	if(new_msg==NULL)
		return -EINVAL;
	message_add_record(new_msg,pcrquote);

	ret=ex_module_sendmsg(sub_proc,new_msg);
	return ret;
}

int proc_pcrquote_verify(void * sub_proc,RECORD(TCM_PIK_DESC,PCRQUOTE) * pcrquote,void * recv_msg)
{
	int ret=0;

	BYTE local_uuid[DIGEST_SIZE];	
	
	BYTE Namebuf[DIGEST_SIZE*4];
	UINT32 result;

	RECORD(TCM_KEY_DESC,VERIFY_DESC) verify_desc;

        RECORD(TCM_KEY_DESC,REMOTE_KEYSET) * remote_keyset;
    	TCM_PUBKEY * verifypubkey;
	int blob_len;
	int BufLen;
    	TCM_QUOTE_INFO * quoteInfo;	

	printf("begin quote report verify !\n");

	remote_keyset=remote_keyset_get_byname(pcrquote->userinfo.username);
	if(remote_keyset==NULL)
		return -EINVAL;

	printf("get remote keyset !\n");
    	verifypubkey=malloc(sizeof(*verifypubkey));
    	if(verifypubkey==NULL)
        	return -EINVAL;

	get_uuid_name(remote_keyset->pikpub_uuid,Namebuf,"pubkey/");
	ret=TCM_ExLoadTcmPubKey(verifypubkey,Namebuf);
	if(ret!=0)
	{
		printf("Load verifypubkey failed!\n");
		return ret;
	}	
	printf("load pikpub !\n");
    	// Create TCM_QUOTE_INFO
    	quoteInfo=malloc(sizeof(*quoteInfo));
    	if(quoteInfo==NULL)
		return -ENOMEM;
	printf("quote nonce!\n");
	print_bin_data(pcrquote->nonce,DIGEST_SIZE,0);

    	ret=TCM_ExCreateQuoteInfo(quoteInfo,&pcrquote->pcrComp,pcrquote->nonce);
    	if(ret!=0)
    	{
		printf("Create Quote Info succeed!\n");
		return ret;
    	}

    // Verify Quote Info

    	BufLen=memdb_output_blob(quoteInfo,Buf,TYPE_PAIR(VTCM_PCR,TCM_QUOTE_INFO));
    	if(BufLen<0)
		return BufLen;	
  
	printf("Quote verify data!\n");
    	print_bin_data(Buf,BufLen,16);
    	print_bin_data(pcrquote->signData,pcrquote->signLen,16);

	ret=TCM_ExSM2Verify(verifypubkey,pcrquote->signData,pcrquote->signLen,
		Buf,BufLen);
    	printf("TCM_ExSM2Verify verify result is %d!\n",ret);
	verify_desc.result=ret;
	
	//printf("output quote blob!\n");
	blob_len=memdb_output_blob(pcrquote,Buf,TYPE_PAIR(TCM_PIK_DESC,PCRQUOTE));
	if(blob_len<0)
		return -EINVAL;
	vtcm_ex_sm3(verify_desc.object_uuid,1,Buf,blob_len);
	// add keydata in message
	//printf("add verify result!\n");
	ret=message_add_expand_data(recv_msg,TYPE_PAIR(TCM_KEY_DESC,VERIFY_DESC),&verify_desc);
	if(ret<0)
		return -EINVAL;
	ret=ex_module_sendmsg(sub_proc,recv_msg);

	return ret;
}
int proc_pcrquote_expand_report(void * sub_proc,RECORD(TCM_PIK_DESC,PCRQUOTE) * pcrquote,void * recv_msg)
{
	int ret=0;

	BYTE local_uuid[DIGEST_SIZE];	
	BYTE user_name[DIGEST_SIZE];
	
	BYTE Namebuf[DIGEST_SIZE*4];
	BYTE nonce[DIGEST_SIZE];
	UINT32 result;

	MSG_EXPAND * msg_expand;
        RECORD(VTCM_IN_KEY,TCM_BIN_PUBKEY) * pubkey;
        RECORD(TCM_KEY_MANAGE,PRIVATE_KEY) * private_key;
        RECORD(TCM_KEY_DESC,LOCAL_KEYSET) * local_keyset;

	int key_len;
	int blob_len;
    	UINT32 authHandle;
    	UINT32 pikHandle;
    	UINT32 signkeyHandle;
   	    BYTE SignBuf[256];
    	int  Buflen;
    	int SignLen;

   //   proc_share_data_getvalue("user_name",user_name);
   //   proc_share_data_getvalue("uuid",local_uuid);

        local_keyset=local_keyset_get_byname(pcrquote->userinfo.username);
        if(local_keyset==NULL)
                return -EINVAL;

	    printf("begin key load !\n");

	// get receiver's remote keyset

        TCM_KEY * verifykey;

        verifykey=malloc(sizeof(*verifykey));
        if(verifykey==NULL)
            return -EINVAL;

	    get_uuid_name(local_keyset->pik_uuid,Namebuf,"tcmkey/");
   	    ret = TCM_ExLoadTcmKey(verifykey, Namebuf);
   	 if(ret!=0)
    	{
        	printf("ExLoadTcmKey error!\n");
        	return -EINVAL;
    	}

    	ret=TCM_APCreate(TCM_ET_SMK, NULL, "sss", &authHandle);
    	printf("authHandle is : %x\n",authHandle);
    	if(ret<0)
    	{
        	printf("TCM_APCreate failed!\n");
        	return -EINVAL;
    	}
    	ret=TCM_LoadKey(0x40000000,authHandle,verifykey,&pikHandle);
    	if(ret<0)
    	{
        	printf("TCM_LoadKey failed!\n");
        	return -EINVAL;
    	}
    	ret=TCM_APTerminate(authHandle);
    	if(ret<0)
    	{
		printf("TCM_APTerminate %x failed!\n",authHandle);
		return -EINVAL;	
    	}	
    	// Quote the data
   	ret=TCM_APCreate(TCM_ET_KEYHANDLE, pikHandle, "kkk", &authHandle);
    	printf("pik authHandle is : %x\n",authHandle);
    	if(ret<0)
    	{
		printf("TCM_APCreate failed!\n");
		return -EINVAL;	
    	}	

    	ret=TCM_Quote(pikHandle,authHandle,pcrquote->nonce,&pcrquote->pcrComp,
		SignBuf,&SignLen);

    	ret=TCM_APTerminate(authHandle);
    	if(ret<0)
    	{
		printf("TCM_APTerminate %x failed!\n",authHandle);
		return -EINVAL;	
    	}	

    	ret=TCM_EvictKey(pikHandle);
    	if(ret<0)
    	{
		printf("TCM_EvictKey %x failed!\n",pikHandle);
		return -EINVAL;	
    	}	

//	new_msg=message_clone(recv_msg);

	pcrquote->signLen=SignLen;
	pcrquote->signData=Talloc0(SignLen);
	Memcpy(pcrquote->signData,SignBuf,SignLen);
	//Strncpy(pcrquote->userinfo.username,local_keyset->user_name,32);
	//Memcpy(pcrquote->userinfo.node_uuid,local_uuid,DIGEST_SIZE);

	ret=message_add_expand_data(recv_msg,TYPE_PAIR(TCM_PIK_DESC,PCRQUOTE),pcrquote);
	if(ret<0)
		return ret;
	ret=ex_module_sendmsg(sub_proc,recv_msg);
	return ret;
}

int proc_pcrquote_expand_verify(void * sub_proc,RECORD(TCM_PIK_DESC,PCRQUOTE) * pcrquote,void * recv_msg)
{
	int ret=0;

	BYTE local_uuid[DIGEST_SIZE];	
	
	BYTE Namebuf[DIGEST_SIZE*4];
	UINT32 result;

	RECORD(TCM_KEY_DESC,VERIFY_DESC) verify_desc;

        RECORD(TCM_KEY_DESC,REMOTE_KEYSET) * remote_keyset;
    	TCM_PUBKEY * verifypubkey;
	int blob_len;
	int BufLen;
    	TCM_QUOTE_INFO * quoteInfo;	

	printf("begin quote report verify !\n");

	remote_keyset=remote_keyset_get_byname(pcrquote->userinfo.username);
	if(remote_keyset==NULL)
		return -EINVAL;

	printf("get remote keyset !\n");
    	verifypubkey=malloc(sizeof(*verifypubkey));
    	if(verifypubkey==NULL)
        	return -EINVAL;

	get_uuid_name(remote_keyset->pikpub_uuid,Namebuf,"pubkey/");
	ret=TCM_ExLoadTcmPubKey(verifypubkey,Namebuf);
	if(ret!=0)
	{
		printf("Load verifypubkey failed!\n");
		return ret;
	}	
	printf("load pikpub !\n");
    	// Create TCM_QUOTE_INFO
    	quoteInfo=malloc(sizeof(*quoteInfo));
    	if(quoteInfo==NULL)
		return -ENOMEM;
	printf("quote nonce!\n");
	print_bin_data(pcrquote->nonce,DIGEST_SIZE,0);

    	ret=TCM_ExCreateQuoteInfo(quoteInfo,&pcrquote->pcrComp,pcrquote->nonce);
    	if(ret!=0)
    	{
		printf("Create Quote Info succeed!\n");
		return ret;
    	}

    // Verify Quote Info

    	BufLen=memdb_output_blob(quoteInfo,Buf,TYPE_PAIR(VTCM_PCR,TCM_QUOTE_INFO));
    	if(BufLen<0)
		return BufLen;	
  
	printf("Quote verify data!\n");
    	print_bin_data(Buf,BufLen,16);
    	print_bin_data(pcrquote->signData,pcrquote->signLen,16);

	ret=TCM_ExSM2Verify(verifypubkey,pcrquote->signData,pcrquote->signLen,
		Buf,BufLen);
    	printf("TCM_ExSM2Verify verify result is %d!\n",ret);
	verify_desc.result=ret;
	
	//printf("output quote blob!\n");
	blob_len=memdb_output_blob(pcrquote,Buf,TYPE_PAIR(TCM_PIK_DESC,PCRQUOTE));
	if(blob_len<0)
		return -EINVAL;
	vtcm_ex_sm3(verify_desc.object_uuid,1,Buf,blob_len);
	// add keydata in message
	//printf("add verify result!\n");
	ret=message_add_expand_data(recv_msg,TYPE_PAIR(TCM_KEY_DESC,VERIFY_DESC),&verify_desc);
	if(ret<0)
		return -EINVAL;
	ret=ex_module_sendmsg(sub_proc,recv_msg);

	return ret;
}

RECORD(TCM_KEY_DESC,REMOTE_KEYSET) * remote_keyset_get_byname (char * name)
{
	int ret;
	RECORD(TCM_KEY_DESC,REMOTE_KEYSET ) * remote_keyset;
	DB_RECORD * db_record;
	char buf[DIGEST_SIZE];
	int i;
	Memset(buf,0,DIGEST_SIZE);
	Strncpy(buf,name,DIGEST_SIZE);
	
	db_record=memdb_find_first(TYPE_PAIR(TCM_KEY_DESC,REMOTE_KEYSET),"user_name",buf);

	if(db_record==NULL)
		return NULL;
	return db_record->record;

}
RECORD(TCM_KEY_DESC,LOCAL_KEYSET) * local_keyset_get_byname (char * name)
{
	int ret;
	RECORD(TCM_KEY_DESC,LOCAL_KEYSET ) * local_keyset;
	DB_RECORD * db_record;
	char buf[DIGEST_SIZE];
	Memset(buf,0,DIGEST_SIZE);
	Strncpy(buf,name,DIGEST_SIZE);
	db_record=memdb_find_first(TYPE_PAIR(TCM_KEY_DESC,LOCAL_KEYSET),"user_name",buf);

	if(db_record==NULL)
		return NULL;
	return db_record->record;
}

int get_uuid_name(BYTE * uuid, char * name, char * path)
{
	int ret=0;
	
	if(path!=NULL)
	{
		ret=Strlen(path);
		Memcpy(name,path,ret);
	}
	digest_to_uuid(uuid,name+ret);
	name[ret+DIGEST_SIZE*2]=0;
	return ret+DIGEST_SIZE;
}

